/*****************************************************************************
文 件 名: work.c
描    述: DTU工作模块
作    者: 武玉峰
版    本: 1.0
完成日期: 2016.8.19 
修改历史: 
*****************************************************************************/
#include "stdio.h"
#include "string.h"
#include "work.h"
#include "gpio.h"
#include "gprs.h"
#include "rs485.h"
#include "delay.h"
#include "24cxx.h"
#include "timer.h"
#include "adc.h"
#include "usart.h"
#include "config.h"
#include "rtc.h"
#include "sys.h"
#include "fireware_update_extr.h"
#include "collect.h"
 //数据发送到服务器的超时时间，单位0.5秒
#define  SEND_DATA_TO_SERVER_TIMEOUT    30
 //接收缓存区 	

 

 
 
extern u8        _SIM900_ERR ;
extern u8        _SIM900_ERR_SUM ;

extern u8         _IMEI[16];
extern u8         _CurVersion;
extern u16         _UpdateVersion;
extern Config _Config;
 
//485接收缓冲区
extern u8 _RS485_RX_BUF[660];  	

extern u8        _WorkPattern;
extern u16      _TimeOutCount; 
extern u16       _RecordCount; 
 
extern u16  _collectedValues[COLLECT_VALUE_SIZE];
u8   _msgSendOK;
u8   _24C_ERR = 1;

 


/*************************************************
函数名称: HandleMessage
功    能: 处理解析后的数据包
参    数: 无           
返 回 值: 无
*************************************************/
u8 HandleMessage(H20Message * pMessage)
{
	int j=0;
  DebugOut("Handle Received Message:\r\n"); 
		for(j=0;j<20;++j)					 
						DebugOut("%X ",pMessage->HeadBodyData[j]); 
	  
	DebugOut("\r\n"); 
	
     _UpdateVersion=0;
    switch (pMessage->MessageType)
    {
    case MSG_HEARTBEAT:
        break;
    case MSG_SUCCESS:

        //同步服务器发来的时间，时间设置
        DebugOut("Synchronize time with server :%d-%d-%d %d:%d:%d \r\n", 2000 + pMessage->HeadBodyData[2], pMessage->HeadBodyData[3], pMessage->HeadBodyData[4],
             pMessage->HeadBodyData[5], pMessage->HeadBodyData[6], pMessage->HeadBodyData[7]);
        RTC_Set(2000 + pMessage->HeadBodyData[2], pMessage->HeadBodyData[3], pMessage->HeadBodyData[4],
                pMessage->HeadBodyData[5], pMessage->HeadBodyData[6], pMessage->HeadBodyData[7]);
		    _msgSendOK=1;
    
		    DebugOut("New Version:%d\r\n",pMessage->HeadBodyData[8]);
	
			if (pMessage->HeadBodyData[8] !=0)
			{
			 
			 	IWDG_Feed(); 
				_UpdateVersion= pMessage->HeadBodyData[8];
			 
			}
		 
       return 1;
       
    case MSG_FAIL:
			  _msgSendOK=0;
        return  1;
       
    case MSG_DATA:



        break;
		case MSG_CONFIG://远程配置
			
		
		
		
			break;
    default:
        break;
    }
		
		return 0;


}
  



 /*************************************************
函数名称: GetServerTime()
功    能: 获取服务器时间并设置到RTC
参    数: 无
返 回 值: int 成功 1 失败 0
*************************************************/
int GetServerTime()
{
    u32  u32Temp;
	    
    u32Temp =	PrepareConnect(); //准备连接
	 
     if(u32Temp == 1)
     {
				if(StrLen(_Config._ServerIP)>0)
					u32Temp = CIPSTART(_Config._ServerIP, _Config._ServerPort); // 
				else
					 u32Temp = CIPSTART(_Config._ServerDN, _Config._ServerPort); // 
				
				if(u32Temp == 0)
				{
				    return 0;
				}
				else
				{
					  //准备发送到服务器的数据
				
					H20Message *pMessage= GetH20MessageBuffer();
					pMessage->FirmwareVersion=CURRENT_FIRMWARE_VERSION;
					pMessage->ProtocolVersion=4; 
					sprintf((char *)&pMessage->IMEI, "%s", _IMEI);
					pMessage->MessageType=MSG_DATA;
					pMessage->BodyLength=0;  
					pMessage = SendH20MsgToServerSync(pMessage, SEND_DATA_TO_SERVER_TIMEOUT);  
					HandleMessage(pMessage);
				 
					 return 1;
				} 
				
    }
		else
			return 0;
		
}
/*************************************************
函数名称: Sys_Standby
功    能: 使STM32进入待机状态
参    数: 无 
返 回 值: 无
*************************************************/
void Sys_Standby(void)
{  
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE); 
	PWR_WakeUpPinCmd(ENABLE);  
	PWR_EnterSTANDBYMode();	    
}
 
 /*************************************************
函数名称:  PrepareDataToSend()
功    能: 准备发送到服务器的数据，如果有离线数据会捎带最多四条离线数据。
参    数: 无
返 回 值: 无
*************************************************/
H20Message * PrepareMessageToSend(u8 * OfflineRecordCount4Send)
{
   u16 j=0;
	u32 u32Temp=0;

    H20Message *pMessage= GetH20MessageBuffer();
	pMessage->FirmwareVersion=CURRENT_FIRMWARE_VERSION;
	pMessage->ProtocolVersion=PROTOCOL_VERSION; 
	sprintf((char *)&pMessage->IMEI, "%s", _IMEI);
	pMessage->MessageType=MSG_DATA;
 
	
	//准备当前最新采集的记录
	//时间自 1970-01-01 的秒数
		u32Temp = RTC_GetCounter();
		for(j = 0; j < 4; ++j)
		{
			pMessage->HeadBodyData[23-j] = (u32Temp >> (8 * j)) & 0xff;
		}
 
		for( j = 0; j < sizeof(_collectedValues)/sizeof(_collectedValues[0]); ++j)
		{

			pMessage->HeadBodyData[24+2*j] = (_collectedValues[j] >> 8) & 0xff;
			pMessage->HeadBodyData[24+2*j+1] = _collectedValues[j] & 0xff;

		}
		
		
		
		j = 24 + 2 * j; // 
		*OfflineRecordCount4Send = 0;
		//24C256中有未发送到服务器的离线数据，为保持数据一致性
		//只有当离线数据真正从服务器发送成功才使 _RecordCount减小，但是也不能完全保证一致
		__set_FAULTMASK(1);
		while(_RecordCount - *OfflineRecordCount4Send > 0 && *OfflineRecordCount4Send < 2) //缓冲区大小为1200最多只能携带2条
			{//注意  E2_RECORD_SIZE 的大小，携带的离线数据不要超过缓冲区大小
			AT24CXX_Read(E2_DATA_BASE_ADDR + (_RecordCount - *OfflineRecordCount4Send - 1)*E2_RECORD_SIZE, &(pMessage->HeadBodyData[j]), E2_RECORD_SIZE);
			j += E2_RECORD_SIZE;
			++*OfflineRecordCount4Send;
			IWDG_Feed();
		}
		__set_FAULTMASK(0);
	 
	  
		
		pMessage->BodyLength=j-MSGH20_HEAD_LENGTH;
		
		
		return  pMessage;


}

 /*************************************************
函数名称:  SaveDataToE2()
功    能: 将离线数据存储到24c256中
参    数: 无
返 回 值: 当前离线数据条数
*************************************************/
u16 SaveDataToE2(u8 * pData)
{
	u8 result=0;
 //3次发送都失败后，把数据存入 24C256
	DebugOut("write data to 24c256\r\n");
  __set_FAULTMASK(1);  //关中断；
	// 采集到的数据写入24c256			
	result = AT24CXX_Write(E2_DATA_BASE_ADDR + _RecordCount * E2_RECORD_SIZE, pData, E2_RECORD_SIZE);
	if(result == 0)
	{
			delay_ms(50);
			result = AT24CXX_Write(E2_DATA_BASE_ADDR + _RecordCount * E2_RECORD_SIZE, pData, E2_RECORD_SIZE);
			_24C_ERR &= result;
	}



	++_RecordCount;
	//写入记录个数
	result = AT24CXX_Write(E2_CFG_ADDR_RECORDCOUNT, (u8 *)&_RecordCount, 2);
	if(result == 0)
	{
			delay_ms(50);
			result = AT24CXX_Write(E2_CFG_ADDR_RECORDCOUNT, (u8 *)&_RecordCount, 2);
			_24C_ERR &= result;
	}

  __set_FAULTMASK(0);//开中断

	if(_RecordCount >E2_MAX_RECORD_COUNT)
	{
			_RecordCount = 0;
	}
	
	return _RecordCount; 

}

 /*************************************************
函数名称: WorkHandler
功    能: stm32的工作函数，主要流程1.采集数据 2.数据发送到服务器 3.进入待机模式
参    数: 无
返 回 值: 无
*************************************************/
void WorkHandler()
{
 
		u32  Wakeuptime;
    u32  u32Temp;
    u8   connected = 0;
    u8   OfflineRecordCount4Send = 0; //发送的离线数据条数
    u8   k=0;
    u8   DataHaveSaved = 0; //数据是否已保存
    u16  firstSyncTime=0;
		H20Message * pMessage=0;
	  DebugOut("- - - - - - - Start Work - - - - - - - \r\n");
	
		
	
		firstSyncTime	=BKP_ReadBackupRegister(BKP_DR5);
		if(firstSyncTime!=0x5050)
		{
			syncTime:
			DebugOut("Get server time !\r\n");
				u32Temp=GetServerTime();
				if(u32Temp>0) 
					DebugOut("Get server time success!\r\n");
				else
				{
					DebugOut("Get server time fail!\r\n");	
					if(++k<=2)
						goto syncTime;
				}
				 BKP_WriteBackupRegister(BKP_DR5, 0x5050);	//进入工作状态
	  }

		Wakeuptime=RTC_GetCounter()+_Config._collectInterval*60;
	   _UpdateVersion=0;
		
		

	if (_UpdateVersion != _CurVersion && _UpdateVersion>0)
	{

		 StartUpdate(_UpdateVersion,(char *)_IMEI,(const char *)_Config._UpdateServerDN,(const char *)_Config._UpdateServerPort);
	}
	
 
		//采集数据
   CollectData();
	

  

		IWDG_Feed();
 
   
				PrepareConnect();
	 //准备数据
		    pMessage= PrepareMessageToSend(&OfflineRecordCount4Send);
	

	
		if(StrLen(_Config._ServerIP)>0)
			 u32Temp = CIPSTART(_Config._ServerIP, _Config._ServerPort); // 
		else
			 u32Temp = CIPSTART(_Config._ServerDN, _Config._ServerPort); // 
 
			if(u32Temp == 0)
			{
					
			}
			else
			{
					DebugOut("CIPSTART command OK\r\n");
					connected = 1 ;
			}
		 



		DebugOut("connected:%d  DataHaveSaved:%d   RecordCount:%d\r\n", connected, DataHaveSaved, _RecordCount);

		if(connected == 0  )
		{
			
				SaveDataToE2(pMessage->HeadBodyData+MSGH20_HEAD_LENGTH);
				DataHaveSaved = 1; 
		}
		else
		{

			 
       
				DebugOut("Send data to server\r\n");
                //备份要发送的数据，当发送失败时写入E2
        memset(_RS485_RX_BUF, '\0', sizeof(_RS485_RX_BUF));
			  memcpy(&_RS485_RX_BUF,pMessage->HeadBodyData+MSGH20_HEAD_LENGTH,E2_RECORD_SIZE);
		  	_UpdateVersion=0;
			  _msgSendOK=0;
		
				pMessage = SendH20MsgToServerSync(pMessage, SEND_DATA_TO_SERVER_TIMEOUT ); 
		    HandleMessage(pMessage);
				//等待从服务器端发来的响应 
				DebugOut("msg send ok:%d\r\n", _msgSendOK);




				u32Temp=CloseConnect();
				if(u32Temp == 0)
				{
						DebugOut("colse connect fail\r\n");
				}
				else
				{
						DebugOut("colse connect success\r\n");
				}
	 


				if(_msgSendOK == 0)
				{
						CONLED = 0;
						delay_ms(500);
						CONLED = 1;                   
					
						DebugOut("Send data to server fail!\r\n");
						//如果连接成功，但是发送失败，此时并没有存储数据，这里要存储一下
						if(DataHaveSaved == 0)
						{
							SaveDataToE2(_RS485_RX_BUF);
							 
						} 
				}
				else
				{


						CONLED = 0;
						delay_ms(500);
						CONLED = 1;
						delay_ms(500);
						CONLED = 0;
						delay_ms(500);
						CONLED = 1;
						CONLED = 0;
						delay_ms(500);
						CONLED = 1;
						DebugOut("Send data to server success\r\n");		

						//发送成功
						_RecordCount -= OfflineRecordCount4Send;
						//保存
					  
					 //写入记录个数
					  __set_FAULTMASK(1);
						AT24CXX_Write(E2_CFG_ADDR_RECORDCOUNT , (u8 *)&_RecordCount, 2);
					 	  __set_FAULTMASK(0);
					
					  	if (_UpdateVersion != _CurVersion && _UpdateVersion>0)
							{

								 StartUpdate(_UpdateVersion,(char *)_IMEI,(const char *)_Config._UpdateServerDN,(const char *)_Config._UpdateServerPort);
							}
				}
		}//if(connected==1) 
		    
		DebugOut("I will wake up after %d minites,bye!\r\n",_Config._collectInterval);	
    IWDG_Feed();		
	        u32Temp= Wakeuptime;//-RTC_GetCounter();		
	   PWR_BackupAccessCmd(ENABLE);		
 				  BKP_WriteBackupRegister(BKP_DR1, (u16)(u32Temp>>16));//写入当前时间
		      BKP_WriteBackupRegister(BKP_DR2, (u16)(u32Temp & 0xffff));
			PWR_BackupAccessCmd(DISABLE);
 			  Sys_Standby();  
}


/**********************************************************************************************************************/
